package com.example.sampleapp;

import static android.app.Activity.RESULT_OK;
import static com.example.sampleapp.R.layout.activity_main;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;

import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.Priority;
import com.iperf3.jni.Iperf3Callback;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;

import com.example.sampleapp.databinding.FragmentFirstBinding;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.time.LocalDateTime;
import java.util.ArrayList;

import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;

public class FirstFragment extends Fragment implements Iperf3Callback {

    private FragmentFirstBinding binding;

    private View view;
    private DatagramSocket socket;
    private Button bt_test;
    private DatagramPacket datagramPacket;
    private EditText et_ip;
    private EditText et_ping;
    private EditText et_speed;
    private EditText et_rssi;
    private EditText et_rate;
    private EditText et_lon;
    private EditText et_lat;
    private EditText et_filename;
    private String rssi;
    private  String rate;
    private String filename;
    private String str_concurrent;
    private StringBuffer tv_PingInfo;
    private String delay;

    private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
    private FusedLocationProviderClient fusedLocationClient;
    private LocationCallback locationCallback;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    private void requestSAF() {
        Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("text/csv");
        intent.putExtra(Intent.EXTRA_TITLE, "data.csv");

        startActivityForResult(intent, 1);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
        super.onActivityResult(requestCode, resultCode, resultData);
        if (requestCode == 1 && resultCode == RESULT_OK) {
            // 获取用户选择的目录的 URI
            Uri uri = resultData.getData();
            writeFileToExternalStorage(uri);
        }
    }

    private void writeFileToExternalStorage(Uri uri) {
        File internalFile = new File(getActivity().getExternalFilesDir(null), filename);
        FileInputStream fileInputStream = null;
        InputStream inputStream = null;
        OutputStream outputStream = null;

        try {
            fileInputStream = new FileInputStream(internalFile);
            //inputStream = getActivity().getContentResolver().openInputStream(uri);
            outputStream = getActivity().getContentResolver().openOutputStream(uri);

            byte[] buffer = new byte[1024];
            int length;
            while ((length = fileInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public View onCreateView(
            LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState
    ) {
        binding = FragmentFirstBinding.inflate(inflater, container, false);
        view = binding.getRoot();
        et_ip = (EditText) view.findViewById(R.id.editText_ip);
        et_rssi = (EditText) view.findViewById(R.id.editText_rssi);
        et_rate = (EditText) view.findViewById(R.id.editText_rate);
        et_lon = (EditText) view.findViewById(R.id.editText_longitude);
        et_lat = (EditText) view.findViewById(R.id.editText_latitude);
        et_filename = (EditText) view.findViewById(R.id.editText_filename);
        et_ping = (EditText) view.findViewById(R.id.editTextPing);
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(getActivity());

        et_lon.setText("0");
        et_lat.setText("0");

        // Check for permission
        if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            // Request the permission
            ActivityCompat.requestPermissions(getActivity(),
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    LOCATION_PERMISSION_REQUEST_CODE);
        } else {
            // Start listening for location updates
            startLocationUpdates();
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                getRssiSpeed(getActivity());
            }
        }).start();

        ArrayList<String[]> data = new ArrayList<>();
        data.add(new String[]{"Time", "Latitude", "Longitude", "rssi", "rate"});

//        File directory = getActivity().getExternalFilesDir(null);
//        et_ip.setText("192.168.1.100");
        //TableToFile.appendToCSV(getActivity().getApplicationContext(), filename, data);

        return view;
    }

    @Override
    public void onStart() {
        super.onStart();
        startLocationUpdates();
    }

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        binding.buttonTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        getPing(et_ip.getText().toString());
                    }
                }).start();

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(11000);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        saveCSV();
                    }
                }).start();
            }
        });

        binding.buttonSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 请求 SAF 权限
                requestSAF();
            }
        });
    }

    public void saveCSV(){
        String str_delay = tv_PingInfo.toString();
        Log.e("savecsv", str_delay);
        if(str_delay.contains("min/avg/max/mdev = ")) {
            String tmp1 = str_delay.split("min/avg/max/mdev")[1];
            delay = tmp1.split("/")[1];
        }else{
            delay = "null";
        }
        filename = et_filename.getText().toString();
        LocalDateTime now = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            now = LocalDateTime.now();
        }
        ArrayList<String[]> data = new ArrayList<>();
        data.add(new String[]{""+now, et_lat.getText().toString(), et_lon.getText().toString(), rssi, rate, delay});
        Log.e("sample", now + " " + et_lat.getText().toString() + " " + et_lon.getText().toString() + " " + rssi + " " + rate + " " + delay);
        TableToFile.appendToCSV(getActivity().getApplicationContext(), filename, data);

    }
    private void startLocationUpdates() {
        LocationRequest locationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 1000).build();

        locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                if (locationResult != null) {
                    for (Location location : locationResult.getLocations()) {
                        // Handle location updates
                        //Log.d("LocationUpdate", "Latitude: " + location.getLatitude() + ", Longitude: " + location.getLongitude());
                        et_lon.setText(location.getLongitude() + "°");
                        et_lat.setText(location.getLatitude() + "°");
                    }
                }
            }
        };

        if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null);
    }

    private void getPing(String m_strForNetAddress) {
        tv_PingInfo = new StringBuffer();
        try {
            Process p = Runtime.getRuntime().exec("/system/bin/ping -c 10" + " " + m_strForNetAddress);
            BufferedReader buf = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String str = new String();
            while ((str = buf.readLine()) != null) {
                str = str + "\r\n";
                tv_PingInfo.append(str);
                int len = tv_PingInfo.length();
                Log.e("ping", str);
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        et_ping.setText(tv_PingInfo.toString());
                        et_ping.setSelection(len);
                    }
                });
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void getLocation(Context context){
        LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
//            if(ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.ACCESS_FINE_LOCATION)) {
//                new AlertDialog.Builder((Activity) context)
//                        .setTitle("操作提示")
//                        .setMessage("是否打开定位权限")
//                        .setPositiveButton(android.R.string.ok,
//                                new DialogInterface.OnClickListener() {
//                                    @Override
//                                    public void onClick(DialogInterface dialogInterface, int i) {
//                                        // Request permission again.
//                                        ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
//                                    }
//                                })
//                        .create()
//                        .show();
//            }
            ActivityCompat.requestPermissions((Activity) context,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    1);
        }
        Location location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
        while(true) {
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (location != null) {
                        et_lon.setText(location.getLongitude() + "°");
                        et_lat.setText(location.getLatitude() + "°");
                    } else {
                        et_lon.setText("null");
                        et_lat.setText("null");
                    }
                }
            });
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    private void getRssiSpeed (Context context) {
        while (true) {
            try {
                WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
                WifiInfo wifiInfo = wifiManager.getConnectionInfo();
                //String ipAddress = Formatter.formatIpAddress(wifiInfo.getIpAddress());
                rssi = Integer.toString(wifiInfo.getRssi());
                rate = Integer.toString(wifiInfo.getLinkSpeed());
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        et_rssi.setText(rssi + "  dBm");
                        et_rate.setText(rate + "  Mbps");
                    }
                });
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void getSpeed(String m_strForNetAddress){
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                et_speed.setText("测速中...");
            }
        });
        StringBuffer tv_PingInfo = new StringBuffer();
        try {
            Process p = Runtime.getRuntime().exec("iperf3 -c " + m_strForNetAddress + " -P " + str_concurrent);
            BufferedReader buf = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String str = new String();
            while ((str = buf.readLine()) != null) {
                str = str + "\r\n";
                tv_PingInfo.append(str);
                int len = tv_PingInfo.length();
                Log.e("iperf3", str);
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        et_speed.setText(tv_PingInfo.toString());
                        et_speed.setSelection(len);
                    }
                });
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
//    private Iperf3Client iperf3Client;
//    private void getSpeed(Context context, String ipStr) {
//        Iperf3Config config = new Iperf3Config(ipStr, 5201, 1);
//        config.bandwidth = 1000 * Iperf3Config.BANDWIDTH_1M;
//        config.isDownMode = true;
//
//        iperf3Client = new Iperf3Client(this);
//        iperf3Client.exec(config);
//    }


    @Override
    public void onResume(){
        super.onResume();
        startLocationUpdates();
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (fusedLocationClient != null && locationCallback != null) {
            fusedLocationClient.removeLocationUpdates(locationCallback);
        }
    }
    @Override
    public void onResult(float timeStart, float timeEnd, String sendBytes, String bandWidth, boolean isDown){
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Log.d("OnResult", timeStart + " " + timeEnd + " " + sendBytes + " " + bandWidth + " ");
                et_speed.setText("[SUM]" + timeStart + " " + timeEnd + " " + sendBytes + " " + bandWidth + " ");
            }
        });
    }

    @Override
    public void onError(String errMsg) {
        Log.e("onError", errMsg);
        et_speed.setText(errMsg);
    }

    @Override
    public void onConnecting(String destHost, int destPort) {

    }

    @Override
    public void onConnected(String localAddr, int localPort, String destAddr, int destPort) {

    }

    @Override
    public void onInterval(float timeStart, float timeEnd, String sendBytes, String bandWidth, boolean isDown){
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Log.d("onInterval", timeStart + " " + timeEnd + " " + sendBytes + " " + bandWidth + " ");
                et_speed.setText(timeStart + " " + timeEnd + " " + sendBytes + " " + bandWidth + " ");
            }
        });
    }

    private  String encodeHexString(byte[] data)
    {
        StringBuilder sb = new StringBuilder();
        for(byte b : data)
        {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
}